import fs from "fs";
import path from "path";
import WebSocket from "ws";
import libopusPackage from 'libopus.js';
import { parseAndSaveOpusFrames } from "./decode.js";

const SERVER = "ws://www.hanxiaoxin.cn:4000";

let opusEncoder;
let opusDecoder;
let wsClient;

const audioParams = {
    sampleRate: 16000,
    channels: 1,
    frameSize: 960,
    maxPacketSize: 4000,
};

// Opus常量
const OPUS_APPLICATION_VOIP = 2048;
const OPUS_APPLICATION = OPUS_APPLICATION_VOIP;

// 配置参数
const CONFIG = {
    framesPerChunk: 30,  // 每个OPUS文件包含的帧数
    outputDir: './opus_chunks',  // 输出目录
    chunkPrefix: 'chunk_'  // 文件前缀
};

// 等待模块初始化的Promise
function waitForModuleReady() {
    return new Promise((resolve, reject) => {
        console.log('开始等待libopus模块初始化...');
        let mod = libopusPackage;
        console.log('mod的键:', Object.keys(mod));
        resolve(mod);
    });
}

async function initOpus() {
    try {
        console.log('libopusPackage类型:', typeof libopusPackage);
        const mod = await waitForModuleReady();
        try {
            // 使用高级API创建编码器
            opusEncoder = new mod.Encoder({
                rate: audioParams.sampleRate,
                channels: audioParams.channels,
                application: mod.Encoder.Application.VOIP
            });
            console.log('Opus编码器创建成功');

            // 使用高级API创建解码器
            opusDecoder = new mod.Decoder({
                rate: audioParams.sampleRate,
                channels: audioParams.channels
            });
            console.log("Opus解码器初始化成功！");
            return true;

        } catch (error) {
            throw new Error(`Opus初始化失败: ${error.message}`);
        }
    } catch (error) {
        console.error("Opus 初始化失败:", error);
        return false;
    }
}

function initWSServer() {
    wsClient = new WebSocket(SERVER, {
        headers: {
            "Device-Id": "libopus-client",
            "Client-Id": "123",
        },
    });

    return new Promise((resolve) => {
        wsClient.on("open", () => {
            console.log(`\nWebSocket 连接成功`);
            resolve();
        });

        wsClient.on("error", (err) => {
            console.error("WebSocket 错误:", err);
        });

        wsClient.on("close", () => {
            console.log("WebSocket 连接已关闭。");
        });
    });
}

// 生成完整的OPUS文件头
function generateOpusHeader(sampleRate = 16000, channels = 1, preSkip = 0) {
    const header = new ArrayBuffer(25);  // 25字节，与app.js匹配
    const view = new DataView(header);
    const uint8Array = new Uint8Array(header);
    
    // "OpusHead" 标识 (8字节)
    const opusHead = "OpusHead";
    for (let i = 0; i < 8; i++) {
        uint8Array[i] = opusHead.charCodeAt(i);
    }
    
    // 版本号 (1字节)
    uint8Array[8] = 1;
    
    // 通道数 (1字节)
    uint8Array[9] = channels;
    
    // 预跳过样本数 (2字节, 小端序)
    view.setUint16(10, preSkip, true);
    
    // 采样率 (4字节, 小端序)
    view.setUint32(12, sampleRate, true);
    
    // 输出增益 (2字节, 小端序)
    view.setUint16(16, 0, true);
    
    // 通道映射 (1字节)
    uint8Array[18] = 0;
    
    // 自定义扩展信息 (6字节)
    // 帧大小 (2字节, 小端序)
    view.setUint16(19, 960, true);  // 帧大小
    // 总帧数 (4字节, 小端序) - 这个会在createOpusFileWithFrames中设置
    view.setUint32(21, 0, true);    // 先设为0，后面会更新
    
    return uint8Array;
}

// 清空输出目录的函数
function clearOutputDirectory() {
    const outputDir = CONFIG.outputDir;
    if (fs.existsSync(outputDir)) {
        // 清空输出目录
        const files = fs.readdirSync(outputDir);
        for (const file of files) {
            const filePath = path.join(outputDir, file);
            if (fs.statSync(filePath).isDirectory()) {
                fs.rmSync(filePath, { recursive: true, force: true });
            } else {
                fs.unlinkSync(filePath);
            }
        }
        console.log(`已清空输出目录: ${outputDir}`);
    } else {
        fs.mkdirSync(outputDir, { recursive: true });
    }
}

// 创建包含指定帧数的完整OPUS文件
function createOpusFileWithFrames(opusFrames, frameCount, outputPath) {
    try {
        // 确保输出目录存在
        const outputDir = CONFIG.outputDir;
        if (!fs.existsSync(outputDir)) {
            fs.mkdirSync(outputDir, { recursive: true });
        }
        
        // 生成OPUS文件头
        const header = generateOpusHeader();
        
        // 在文件头中设置正确的总帧数
        const headerView = new DataView(header.buffer);
        headerView.setUint32(21, frameCount, true);  // 在偏移21处设置总帧数（4字节）
        
        // 计算总大小：头部 + 所有帧数据
        const totalSize = header.length + opusFrames.reduce((total, frame) => total + 4 + frame.length, 0);
        
        // 创建ArrayBuffer
        const buffer = new ArrayBuffer(totalSize);
        const uint8Array = new Uint8Array(buffer);
        const view = new DataView(buffer);
        
        let offset = 0;
        
        // 写入文件头
        uint8Array.set(header, offset);
        offset += header.length;
        
        // 写入所有帧数据
        for (const frame of opusFrames) {
            // 写入帧长度
            view.setUint32(offset, frame.length, true);
            offset += 4;
            
            // 写入帧数据
            uint8Array.set(frame, offset);
            offset += frame.length;
        }
        
        // 保存到文件
        fs.writeFileSync(outputPath, uint8Array);
        
        console.log(`成功创建OPUS文件: ${outputPath}`);
        console.log(`包含 ${frameCount} 帧，文件大小: ${totalSize} 字节`);
        
        return outputPath;
        
    } catch (error) {
        console.error('创建OPUS文件失败:', error);
        throw error;
    }
}

// 主要的上传函数：一帧一帧发送，同时按N帧分组保存文件
async function uploadOpusData() {
    try {
        // 在开始处理前清空输出目录
        clearOutputDirectory();
        
        const data = fs.readFileSync("demo.opus");
        console.log(`文件大小: ${data.length} 字节`);

        // 解析自定义OPUS文件格式
        const result = parseAndSaveOpusFrames(new Uint8Array(data), null); // 不保存原始文件
        const opusFrames = result.frames;
        console.log(`解析出 ${opusFrames.length} 个OPUS帧`);

        // 按配置的帧数分组
        const framesPerChunk = CONFIG.framesPerChunk;
        const totalChunks = Math.ceil(opusFrames.length / framesPerChunk);
        
        console.log(`将生成 ${totalChunks} 个OPUS文件，每个文件包含 ${framesPerChunk} 帧`);
        console.log(`WebSocket将一帧一帧发送 ${opusFrames.length} 个帧`);

        const generatedFiles = [];
        let currentChunkFrames = [];

        // 一帧一帧发送，同时收集帧用于文件保存
        for (let i = 0; i < opusFrames.length; i++) {
            const frameData = opusFrames[i];
            
            // 发送当前帧到WebSocket
            try {
                console.log(`帧 ${i + 1}/${opusFrames.length}: ${frameData.length} 字节, 发送中...`);
                await wsClient.send(frameData);
                
                // 可选：添加小延迟以模拟实时传输
                await new Promise(resolve => setTimeout(resolve, 60));
            } catch (error) {
                console.error(`发送帧 ${i + 1} 失败:`, error);
            }
            
            // 收集帧用于文件保存
            currentChunkFrames.push(frameData);
            
            // 当收集到足够的帧数或者是最后一帧时，保存文件
            if (currentChunkFrames.length === framesPerChunk || i === opusFrames.length - 1) {
                const chunkIndex = Math.floor(i / framesPerChunk);
                const outputPath = `${CONFIG.outputDir}/${CONFIG.chunkPrefix}${chunkIndex + 1}.opus`;
                
                // 创建OPUS文件
                const filePath = createOpusFileWithFrames(currentChunkFrames, currentChunkFrames.length, outputPath);
                generatedFiles.push(filePath);
                
                console.log(`保存文件 ${chunkIndex + 1}/${totalChunks}: ${filePath} (${currentChunkFrames.length} 帧)`);
                
                // 清空当前分组，准备下一组
                currentChunkFrames = [];
            }
        }

        console.log(`WebSocket发送完成：成功发送 ${opusFrames.length} 个OPUS帧`);
        console.log(`文件保存完成：成功生成 ${generatedFiles.length} 个OPUS文件`);
        console.log(`文件列表:`, generatedFiles);

        // 关闭WebSocket连接
        if (wsClient && wsClient.readyState === WebSocket.OPEN) {
            wsClient.close();
            console.log('手动关闭连接');
        }

    } catch (error) {
        console.error('处理OPUS数据失败:', error);
        // 发生错误时也要关闭WebSocket连接
        if (wsClient && wsClient.readyState === WebSocket.OPEN) {
            wsClient.close();
            console.log('WebSocket连接已关闭（错误处理）');
        }
    }
}

// 主函数
async function main(config = null) {
    console.log(`=== 开始处理OPUS数据 ===`);
    
    // 更新配置
    if (config) {
        Object.assign(CONFIG, config);
    }
    
    console.log(`配置参数:`, CONFIG);

    await initOpus();
    await initWSServer();
    await uploadOpusData();
}

// 导出函数供外部调用
export { main, CONFIG };